package com.xz.message.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponseBody;
import com.aliyun.tea.TeaException;
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import com.google.gson.Gson;
import com.xz.common.constant.Constants;
import com.xz.common.core.redis.RedisCache;
import com.xz.common.exception.ServiceException;
import com.xz.common.utils.spring.SpringUtils;
import com.xz.message.domain.SysTenantNotifyConfig;
import com.xz.message.vo.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author ZhangZhiJia
 * @date 2023/8/2 15:37
 * @return null
 */
@Component
public class DdapiUtil {

    private static final Logger log = LoggerFactory.getLogger(DdapiUtil.class);

    private RestTemplate restTemplate = new RestTemplate();

    public static com.aliyun.dingtalkoauth2_1_0.Client createClient() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkoauth2_1_0.Client(config);
    }

    /**
     * 获取access_token
     */
    public String getToken(SysTenantNotifyConfig tenantConfig) {
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        String existToken = redisCache.getCacheObject(getCacheKey(tenantConfig.getTenantId()));
        if (StringUtils.isNotBlank(existToken)) {
            log.info("获取缓存中的token");
            return existToken;
        }
        String appKey = tenantConfig.getDdAgentId();
        String appSecret = tenantConfig.getDdCorpSecret();
        return createToken(appKey, appSecret, tenantConfig.getTenantId());
    }

    private String createToken(String appKey, String appSecret, Long tenantId) {
        try {
            com.aliyun.dingtalkoauth2_1_0.Client client = createClient();
            com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest();
            getAccessTokenRequest.setAppKey(appKey);
            getAccessTokenRequest.setAppSecret(appSecret);
            GetAccessTokenResponse accessToken = client.getAccessToken(getAccessTokenRequest);
            GetAccessTokenResponseBody body = accessToken.getBody();
            SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(tenantId), body.getAccessToken(), body.getExpireIn().intValue(), TimeUnit.SECONDS);
            return body.getAccessToken();
        }  catch (Exception _err) {
           log.error("获取钉钉企业accessToken(企业内部应用)异常:"+_err);
           throw new ServiceException("获取钉钉企业accessToken异常");
        }
    }

    public static String getCacheKey(Long tenantId) {
        return Constants.SYS_DDAPI_KEY + tenantId;
    }

    /**
     * 根据手机号查询用户
     */
    public QiWeiOrDingDingUser getbymobile(SysTenantNotifyConfig tenantConfig,String mobile) {
        String token = getToken(tenantConfig);
        Map<String, Object> param = new HashMap<>();
        param.put("mobile", mobile);
        param.put("support_exclusive_account_search", true);
        String res = doPost("https://oapi.dingtalk.com/topapi/v2/user/getbymobile?access_token=" + token , requestBody -> {
            requestBody.putAll(param);
        });
        JSONObject body = JSONObject.parseObject(res);
        if("0".equals(body.getString("errcode"))){
            String userid = body.getJSONObject("result").getString("userid");
            return  getbyUserId(userid,token);
        }else{
            throw new ServiceException("根据手机号查找钉钉用户失败,失败原因:"+body.getString("errmsg"));
        }
    }
    public QiWeiOrDingDingUser getbyUserId(String userId,String token) {
        Map<String, Object> param = new HashMap<>();
        param.put("language", "zh_CN");
        param.put("userid", userId);
        String res = doPost("https://oapi.dingtalk.com/topapi/v2/user/get?access_token=" +  token, requestBody -> {
            requestBody.putAll(param);
        });
        JSONObject body = JSONObject.parseObject(res);
        if("0".equals(body.getString("errcode"))){
            return new Gson().fromJson(body.getString("result"), QiWeiOrDingDingUser.class);
        }else{
            throw new ServiceException("根据手机号查找钉钉用户失败,失败原因:"+body.getString("errmsg"));
        }
    }


    /**
     * 发送应用消息
     */
    public DingDingMessageResponse sendMsg(SysTenantNotifyConfig tenantConfig, DingDingMessageBody messageBody) {
        String access_token = getToken(tenantConfig);
        String result = doPost("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=" + access_token, body -> {
            Map<String, Object> jsonObject = JSONObject.parseObject(JSON.toJSONString(messageBody));
            body.putAll(jsonObject);
        });
        Gson gson = new Gson();
        return gson.fromJson(result, DingDingMessageResponse.class);
    }

    /**
     * 发送群机器人消息
     */
    public void sendWebhook(String webhook, DingDingMessageBody messageBody) {
        doPost(webhook, body -> {
            Map<String, Object> jsonObject = JSONObject.parseObject(JSON.toJSONString(messageBody.getMsg()));
            body.putAll(jsonObject);
        });
    }


    /**
     * 调用post请求
     * 参考博文：https://blog.csdn.net/zai_xia/article/details/80926157
     *
     * @param url      接口地址
     * @param function 封装请求参数
     * @return
     */
    public String doPost(String url, Consumer<Map<String, Object>> function) {
        HttpHeaders headers = new HttpHeaders();
        // 以json的方式提交
        headers.setContentType(MediaType.APPLICATION_JSON);
        Map<String, Object> params = new HashMap<>();
        function.accept(params);
        //将请求头部和参数合成一个请求
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(params, headers);
        log.debug("POST访问接口：" + url);
        log.debug("POST body：{}", JSON.toJSONString(params, true));
        //执行HTTP请求，将返回的结构使用ResultVO类格式化
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
        String body = response.getBody();
        log.debug("接口响应：" + body);
        return body;
    }

    /**
     * 调用get接口
     *
     * @param url           接口地址
     * @param queryParamMap query参数
     * @return
     */
    public String doGet(String url, Map<String, String> queryParamMap) {
        //保证map不为空
        if (!CollectionUtils.isEmpty(queryParamMap)) {
            //遍历map拼接参数
            url += queryParamMap.entrySet().stream()
                    .map(entry -> String.format("%s=%s", entry.getKey(), entry.getValue()))
                    .collect(Collectors.joining("&", "?", ""));
        }
        log.debug("访问接口：" + url);
        //接收响应
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
        log.debug("接口响应：" + response.getBody());
        return response.getBody();
    }
}
